#include "GraphErrorCorrector.h"
#include "DissectBubblesCorrector.h"
#include "GraphExaminator.h"
#include <map>
#include<iostream>
#include<fstream>
using namespace std;

SequenceGraph* GraphErrorCorrector::correctGraph()
{
	m_numCorrected = 0;
	RemoveLowMultiplicity* removeMultiplicity = new RemoveLowMultiplicity(m_seqGraph, m_multiplicityThreshold);
	removeMultiplicity->correctGraph();
	GraphExaminator::exam(*m_seqGraph);
	cout << "Remove Low Multiplicity: " <<removeMultiplicity->numCorrected() <<endl;
	m_numCorrected +=  removeMultiplicity->numCorrected();
	delete removeMultiplicity;

	DissectBubblesCorrector* dissectBubbles = new DissectBubblesCorrector(m_seqGraph,m_distBound, m_mismatchUpperBound, m_mismatchLowerBound, m_relativeMismatch);
	dissectBubbles->correctGraph();
	GraphExaminator::exam(*m_seqGraph);
	cout << "Dissect Bubbles: " << dissectBubbles->numCorrected() << endl;
	m_numCorrected +=  dissectBubbles->numCorrected();
	delete dissectBubbles;
	
	RemoveTips* removeTips = new RemoveTips(m_seqGraph, m_lengthThreshold);
	removeTips->correctGraph();
	GraphExaminator::exam(*m_seqGraph);
	cout << "Remove Tips: " << removeTips->numCorrected() << endl;
	m_numCorrected +=  removeTips->numCorrected();
	delete removeTips;

	RemoverLowCoveragePath* removeLowcoverage = new RemoverLowCoveragePath(m_seqGraph, m_coverageThreshold);
	removeLowcoverage->correctGraph();
	GraphExaminator::exam(*m_seqGraph);
	cout << "Remove Low Coverage: " << removeLowcoverage->numCorrected() << endl;
	m_numCorrected +=  removeLowcoverage->numCorrected();
	delete removeLowcoverage;
	
	return m_seqGraph;
}

SequenceGraph* RemoveTips::correctGraph()
{
	cout << "Start remove tips..." <<endl;
	LOG(INFO) << "Start remove tips..." <<endl;
	int mergeNum = 0;
	char* buffer = new char[m_lengthThreshold + KmerVertex::getLength()];
	fstream tipOutfile("../examples/tipVertices.fa", ios::out);
	m_seqGraph->resetCursor();
	while (m_seqGraph->hasNext()) {
		SequenceVertex* seqV = m_seqGraph->next();
		if (seqV->size() - KmerVertex::getLength() + 1 < m_lengthThreshold) {
			// tail dangling
			if (m_seqGraph->numOfSuccessors(seqV) == 0 && m_seqGraph->numOfPredecessors(seqV) == 1) {
				const SequenceEdge onlyPred = (m_seqGraph->getPredecessors(seqV)).front();
				GINT32 multiplicity = m_seqGraph->getMultiplicity(onlyPred.end, seqV);
				const vector<SequenceEdge> rivals(m_seqGraph->getSuccessors(onlyPred.end));
				int rSize = rivals.size();
				for (int i = 0; i < rSize; ++i) {
					SequenceVertex *rival = rivals[i].end;
					if (rival != seqV && rivals[i].multiplicity >= multiplicity) {
						tipOutfile << "> tip relative low multiplicity " << seqV->getVertexID()<<endl;
						tipOutfile << seqV->decompressVertex(*m_seqGraph, buffer) <<endl;
						m_seqGraph->removeVertexAndTwin(seqV);
						seqV = NULL;
						++m_numCorrected;
						if (rSize == 2 && rival->numPredecessors() == 1 && rival != onlyPred.end) {
							assert(onlyPred.end->numSuccessors() == 1);
							assert(rival->numPredecessors() == 1);
							m_seqGraph->mergeVertexIntoLargeIDVertex(onlyPred.end, rival);
							++mergeNum;
						}
						break;
					}
				}
			} // head dangling
			else if (m_seqGraph->numOfPredecessors(seqV) == 0 && m_seqGraph->numOfSuccessors(seqV) == 1) {
				SequenceEdge onlySucc = (m_seqGraph->getSuccessors(seqV)).front();
				GINT32 multiplicity = m_seqGraph->getMultiplicity(seqV, onlySucc.end);
				const vector<SequenceEdge> rivals(m_seqGraph->getPredecessors(onlySucc.end));
				int rSize=rivals.size();
				for (int i = 0; i < rSize; ++i) {
					SequenceVertex *rival = rivals[i].end;
					if (rival != seqV && rivals[i].multiplicity > multiplicity) {
						tipOutfile << "> tip relative low multiplicity " << seqV->getVertexID()<<endl;
						tipOutfile << seqV->decompressVertex(*m_seqGraph, buffer) <<endl;
						m_seqGraph->removeVertexAndTwin(seqV);
						seqV = NULL;
						++m_numCorrected;
						if (rSize == 2 && rival->numSuccessors() == 1 && rival != onlySucc.end) {
							assert(rival->numSuccessors() == 1);
							assert(onlySucc.end->numPredecessors() == 1);
							m_seqGraph->mergeVertexIntoLargeIDVertex(rival, onlySucc.end);
							++mergeNum;
						}
						break;
					}
				}
			} // single dangling 
			else if (m_seqGraph->numOfPredecessors(seqV) == 0 && m_seqGraph->numOfSuccessors(seqV) == 0) {
				tipOutfile << "> tip single dangling " << seqV->getVertexID()<< endl;
				tipOutfile << seqV->decompressVertex(*m_seqGraph, buffer) << endl;
				m_seqGraph->removeVertexAndTwin(seqV);
				seqV = NULL;
				++m_numCorrected;
			} // self loop single dangling
			else if (m_seqGraph->numOfPredecessors(seqV) == 1 && m_seqGraph->numOfSuccessors(seqV) == 1
				&& m_seqGraph->getSuccessors(seqV).front().end == seqV) {
					tipOutfile << "> tip self loop single dangling " << seqV->getVertexID()<< endl;
					tipOutfile << seqV->decompressVertex(*m_seqGraph, buffer) << endl;
					m_seqGraph->removeVertexAndTwin(seqV);
					seqV = NULL;
					++m_numCorrected;
			}
		}
	}
	tipOutfile.close();
	delete[] buffer;
	cout <<"Merge Errors: " <<mergeNum <<endl;
	cout << "Finish remove tips." <<endl;
	LOG(INFO) << "Finish remove tips." << endl;
	return m_seqGraph;
}

SequenceGraph* RemoveLowMultiplicity::correctGraph()
{
	cout << "Start remove low multiplicity..." <<endl;
	LOG(INFO) << "Start remove low multiplicity...";
	ofstream outf("../examples/multiplicityDistribution.txt");
	int numMerged = 0;
	m_seqGraph->resetCursor();
	while (m_seqGraph->hasNext()) {
		SequenceVertex* seqV = m_seqGraph->next();
		const vector<SequenceEdge> preds(seqV->getPredecessors());
		for (int i = 0; i < preds.size(); ++i)
		{
			outf << preds[i].multiplicity << endl;
			if (preds[i].multiplicity < m_multiplicityThreshold)
			{
				m_seqGraph->removeSuccessorAndTwinPredecessor(preds[i].end, seqV);
				++m_numCorrected;
			}
		} // for (int i = 0; i < preds.size(); ++i)
		if (m_seqGraph->numOfPredecessors(seqV) == 1) {
			SequenceVertex* onlyPred = seqV->getPredecessors().front().end;
			if (m_seqGraph->numOfSuccessors(onlyPred) == 1) {
				SequenceVertex* merged = m_seqGraph->mergeVertexIntoLargeIDVertex(onlyPred,seqV);
				if (merged) 
				{
					seqV = merged;
					++numMerged;
				}
			}
		}
		const vector<SequenceEdge> succs(seqV->getSuccessors());
		for (int i = 0; i < succs.size(); ++i) {
			outf << succs[i].multiplicity <<endl;
			if (succs[i].multiplicity < m_multiplicityThreshold) {
				m_seqGraph->removeSuccessorAndTwinPredecessor(seqV, succs[i].end);
				++m_numCorrected;
			}
		} // for (int i = 0; i < succs.size(); ++i)
		if (m_seqGraph->numOfSuccessors(seqV) == 1) {
			SequenceVertex* onlySucc = seqV->getSuccessors().front().end;
			if (m_seqGraph->numOfPredecessors(onlySucc) == 1) {
				if (m_seqGraph->mergeVertexIntoLargeIDVertex(seqV, onlySucc))
				{
					++numMerged;
				}
			}
		}
	} // while (m_seqGraph->hasNext())

	cout <<"MergeError: " << numMerged <<endl;
	outf.close();
	cout << "Finish remove low multiplicity." <<endl;
	LOG(INFO) <<  "Finish remove low multiplicity.";
	return m_seqGraph;
}

//SimpleRemoveBubbles::SimpleRemoveBubbles(SequenceGraph* seqGraph,unsigned int distBound):
//AbstractGraphCorrector(seqGraph), m_visitVertex(new VisitVertex*[seqGraph->maxVertexID()+1])
//{
//	m_distBound=distBound;
//	memset(m_visitVertex, 0, (seqGraph->maxVertexID()+1) * sizeof(VisitVertex*));
//	m_seqGraph->resetCursor();
//	while (m_seqGraph->hasNext()) {
//		m_visitVertex[m_seqGraph->next()->getVertexID()] = new VisitVertex();
//	}
//}
//
//SimpleRemoveBubbles::~SimpleRemoveBubbles()
//{
//	for (GINT32 i = 0; i < m_seqGraph->maxVertexID()+1; ++i) {
//		if (m_visitVertex[i] != NULL) {
//			delete m_visitVertex[i];
//		}
//	}
//	delete[] m_visitVertex;
//}
//
//int VisitVertex::cmp_func(void* node1, void* node2)
//{
//	assert(node1 != NULL && node2 != NULL);
//	VisitVertex* ele1 = (VisitVertex*) node1;
//	VisitVertex* ele2 = (VisitVertex*) node2;
//	if (ele1 == ele2 || ele1->dist == ele2->dist) {
//		return 0;
//	} else if (ele1->dist > ele2->dist) {
//		return 1;
//	} else {
//		return -1;
//	}
//}
//
//int SimpleRemoveBubbles::PathVertex::cmp_func(void* node1, void* node2)
//{
//	assert(node1 != NULL && node2 != NULL);
//	PathVertex* ele1 = (PathVertex*) node1;
//	PathVertex* ele2 = (PathVertex*) node2;
//	if (ele1 == ele2 || ele1->dist == ele2->dist) {
//		return 0;
//	} else if (ele1->dist > ele2->dist) {
//		return 1;
//	} else {
//		return -1;
//	}
//}
//
//vector<SequenceVertex*> SimpleRemoveBubbles::visitedPredecessors(SequenceVertex* v)
//{
//	//	vector<SequenceVertex*> pred = m_seqGraph->getPredecessors(v);
//	vector<SequenceVertex*> & pred = v->getTwinVertex()->m_successorList;
//	vector<SequenceVertex*> ret;
//	for (GUINT32 i = 0; i < pred.size(); ++i) {
//		if (m_visitVertex[pred[i]->getVertexID()]->visited) {
//			ret.push_back(pred[i]);
//		}
//	}
//	return ret;
//}
//
//SequenceGraph* SimpleRemoveBubbles::correctGraph()
//{
//	cout <<  "Start remove bubbles..." <<endl;
//	LOG(INFO) <<  "Start remove bubbles...";
//	SequenceVertex* root = NULL;
//	m_seqGraph->resetCursor();
//	while (root = nextRoot()) {
//		removeBubble(root);
//	}
//	cout <<  "Finish remove bubbles." <<endl;
//	LOG(INFO) <<  "Finish remove bubbles.";
//	return m_seqGraph;
//}
//
//SequenceVertex* SimpleRemoveBubbles::nextRoot()
//{
//	if (m_seqGraph->hasNext()) {
//		SequenceVertex* ret = m_seqGraph->next();
//		if (!m_visitVertex[ret->getVertexID()]->visited && m_seqGraph->numOfPredecessors(ret) == 0) {
//			return ret;
//		}
//	}
//	return NULL;
//}
////void printVertex(SequenceGraph *g,SequenceVertex * root)
////{
////	char vBuffer[100];
////	root->decompressVertex(*g,vBuffer);
////	cout<<"Vertex::"<<endl;
////	cout<<vBuffer<<endl;
////}
//void SimpleRemoveBubbles::removeBubble(SequenceVertex* root)
//{
//	//  printVertex(m_seqGraph,root);	
//	FibHeap minHeap(VisitVertex::cmp_func);
//	GID_T rootId = root->getVertexID();
//	m_visitVertex[rootId]->dist = 0;
//	m_visitVertex[rootId]->inqueue = true;
//	m_visitVertex[rootId]->vidInGraph = rootId;
//	minHeap.insert(m_visitVertex[rootId]);
//	while (!minHeap.isEmpty()) {
//		bool mergeEnd = false;
//		VisitVertex* curVisit = (VisitVertex*)minHeap.extractMin();
//		SequenceVertex* curVertex = m_seqGraph->getVertexByID(curVisit->vidInGraph);
//		//printVertex(m_seqGraph,curVertex);
//		vector<SequenceVertex*> succs = m_seqGraph->getSuccessors(curVertex);
//		for (int i = 0; i < succs.size(); ++i) {
//			GID_T succ_id = succs[i]->getVertexID();
//			if (!m_visitVertex[succ_id]->inqueue) {
//				m_visitVertex[succ_id]->vidInGraph = succ_id;
//				m_visitVertex[succ_id]->dist = curVisit->dist + curVertex->m_numOfKmer;
//				m_visitVertex[succ_id]->inqueue = true;
//				m_visitVertex[succ_id]->predecessor=curVisit;
//				minHeap.insert(m_visitVertex[succ_id]);
//				mergeEnd = false;
//			} else if (!m_visitVertex[succ_id]->visited && curVisit->vidInGraph != succ_id) {
//				double dist = curVisit->dist + curVertex->m_numOfKmer;
//				if (dist < m_visitVertex[succ_id]->dist)
//				{
//					VisitVertex* newVV = new VisitVertex(*m_visitVertex[succ_id]);
//					newVV->dist = dist;
//					newVV->predecessor=curVisit;
//					minHeap.decreaseKey(m_visitVertex[succ_id], newVV);
//					delete m_visitVertex[succ_id];
//					m_visitVertex[succ_id] = newVV;
//				}
//				/*vector<SequenceVertex*> preds = visitedPredecessors(succs[i]);
//				for (GUINT32 j = 0; j < preds.size(); ++j) {
//				mergeEnd = tryMerge(succs[i], preds[j], curVertex);
//				}*/
//				mergeEnd = tryMerge(m_visitVertex[succ_id], m_visitVertex[succ_id]->predecessor, curVisit);
//			} else if (curVisit->vidInGraph != succ_id) {
//				//vector<SequenceVertex*> preds = visitedPredecessors(succs[i]);
//				//for (GUINT32 j = 0; j < preds.size(); ++j) {
//				mergeEnd = tryMerge(m_visitVertex[succ_id], m_visitVertex[succ_id]->predecessor, curVisit);
//				//}
//			}
//		}
//		curVisit->visited = true;
//		// begin to merge end part, start part has been done in tryMerge
//		if (mergeEnd && succs.size() == 1 && !m_visitVertex[succs[0]->getVertexID()]->visited
//			&& m_seqGraph->numOfPredecessors(succs[0]) == 1) {
//				//			SequenceVertex* predV = m_seqGraph->getPredecessors(succs[0])[0];
//				SequenceVertex* predV = m_seqGraph->getSuccessors(succs[0]->getTwinVertex())[0]->getTwinVertex();
//				GINT64 preId = predV->getVertexID(); // must have visited
//				GINT64 endId = succs[0]->getVertexID();
//				m_visitVertex[preId]->visited = false;
//				minHeap.decreaseKey(m_visitVertex[endId], m_visitVertex[preId]);
//				m_seqGraph->mergeVertexIntoPred(predV, succs[0]);
//		}
//		else if(mergeEnd && succs.size() == 1 && m_visitVertex[succs[0]->getVertexID()]->visited
//			&& m_seqGraph->numOfPredecessors(succs[0]) == 1) {
//				//				SequenceVertex* predV = m_seqGraph->getPredecessors(succs[0])[0];
//				SequenceVertex* predV = m_seqGraph->getSuccessors(succs[0]->getTwinVertex())[0]->getTwinVertex();
//				GINT64 preId = predV->getVertexID(); // must have visited
//				GINT64 endId = succs[0]->getVertexID();
//				//m_visitVertex[preId]->visited = false;
//				//minHeap.decreaseKey(m_visitVertex[endId], m_visitVertex[preId]);
//				m_seqGraph->mergeVertexIntoPred(predV, succs[0]);
//		}
//	}
//}
//
//bool SimpleRemoveBubbles::tryMerge(VisitVertex* end, VisitVertex* pre1, VisitVertex* pre2)
//{
//	deque<VisitVertex *>path1,path2;
//	VisitVertex *start=find2Paths(pre1,pre2,&path1,&path2);
//	if(start==NULL)
//		return false;
//	deque<VisitVertex*>* mergedPath = NULL;
//	if (path1.size() == 1|| path2.size() == 1)
//		mergedPath = merge(start, &path1, &path2, end); // here P must be either P1 or P2
//	else
//	{
//		++m_numCorrected;
//		return false;
//	}
//	if (mergedPath != NULL) {
//		deque<VisitVertex*>* toKeep, * toRemove;
//		if (mergedPath == &path1) {
//			toKeep = &path1;
//			toRemove = &path2;
//		} else {
//			toKeep = &path2;
//			toRemove = &path1;
//		}
//		// merge parallelly
//		removePath(toRemove);
//		++m_numCorrected;
//		// begin merge serially
//		SequenceVertex * SeqStart=m_seqGraph->getVertexByID(start->vidInGraph);
//		if (m_seqGraph->numOfSuccessors(SeqStart) == 1) {
//			SequenceVertex* succV = m_seqGraph->getSuccessors(SeqStart)[0];
//			if (m_seqGraph->numOfPredecessors(succV) == 1) {
//				m_seqGraph->mergeVertexIntoPred(SeqStart, succV);
//			}
//		} // since end my not be visited yet, heap element may be affected
//		return true;
//	}
//	return false;
//}
//
//int SimpleRemoveBubbles::BFSPathLength(VisitVertex *LastNode)
//{
//	int n=0;
//	while(LastNode!=NULL)
//	{
//		n++;
//		LastNode=LastNode->predecessor;
//	}
//	return n;
//}
//VisitVertex* SimpleRemoveBubbles::find2Paths(VisitVertex* pre1, VisitVertex* pre2, deque<VisitVertex*>* path1, deque<VisitVertex*>* path2)
//{
//	//	cout<<"find2Paths"<<endl;
//	//	cout<<"pre1:  ";
//	//	printVertex(m_seqGraph,m_seqGraph->getVertexByID(pre1->vidInGraph));
//	//	cout<<"pre2:  ";
//	//printVertex(m_seqGraph,m_seqGraph->getVertexByID(pre2->vidInGraph));
//	int Path1Len=BFSPathLength(pre1);
//	int Path2Len=BFSPathLength(pre2);
//	VisitVertex *end1,*end2;
//	end1=pre1;
//	end2=pre2;
//	int difDistance;
//	int i,dist1,dist2;
//	dist1=dist2=0;
//	if(Path1Len>=Path2Len)
//	{
//		difDistance=Path1Len-Path2Len;
//		for(i=0;i<difDistance;i++)
//		{
//			path1->push_back(end1);
//			dist1+=(m_seqGraph->getVertexByID(end1->vidInGraph)->m_numOfKmer);
//			end1=end1->predecessor;		
//		}
//	}
//	else
//	{
//		difDistance=Path1Len-Path2Len;
//		for(i=0;i<difDistance;i++)
//		{
//			path2->push_back(end2);
//			dist2+=(m_seqGraph->getVertexByID(end2->vidInGraph)->m_numOfKmer);
//			end2=end2->predecessor;
//		}
//	}
//	while(end1!=end2&&end1!=NULL&&end2!=NULL&&dist1<m_distBound&&dist2<m_distBound)
//	{
//		path1->push_back(end1);
//		path2->push_back(end2);
//		dist1+=(m_seqGraph->getVertexByID(end1->vidInGraph)->m_numOfKmer);
//		dist2+=(m_seqGraph->getVertexByID(end2->vidInGraph)->m_numOfKmer);
//		end1=end1->predecessor;
//		end2=end2->predecessor;
//	}
//	if(end1!=end2)
//		return NULL;
//	return end1;
//}
//
//deque<VisitVertex*> *SimpleRemoveBubbles::merge(VisitVertex* start, deque<VisitVertex*>* path1, deque<VisitVertex*>* path2,VisitVertex* end)
//{
//	int bufferSize = m_distBound + 1;
//	char* path1seq = new char[bufferSize];
//	char* path2seq = new char[bufferSize];
//	char* buffer = new char[bufferSize*2];
//	SequenceVertex *tempVertex;
//	SequenceVertex *SeqStart=m_seqGraph->getVertexByID(start->vidInGraph);
//	path1seq[0] = '\0'; path2seq[0] = '\0';
//	for (GUINT32 i = 0; i < path1->size(); ++i) {
//		tempVertex=m_seqGraph->getVertexByID((*path1)[i]->vidInGraph);
//		tempVertex->decompressVertex(*m_seqGraph, buffer);
//		strcat(path1seq, buffer + KmerVertex::getLength() - 1);
//	}
//	for (GUINT32 i = 0; i < path2->size(); ++i) {
//		tempVertex=m_seqGraph->getVertexByID((*path2)[i]->vidInGraph);
//		tempVertex->decompressVertex(*m_seqGraph, buffer);
//		strcat(path2seq, buffer + KmerVertex::getLength() - 1);
//	}
//	if (strcmp(path1seq+1, path2seq+1) == 0 || strcmp(path1seq, path2seq+1) == 0
//		|| strcmp(path1seq+1, path2seq) == 0) { // similar enough
//			delete[] buffer, path1seq, path2seq;
//			tempVertex=m_seqGraph->getVertexByID((*path1)[0]->vidInGraph);
//			//printVertex(m_seqGraph,SeqStart);
//			//printVertex(m_seqGraph,tempVertex);
//			double multi1 = m_seqGraph->getMultiplicity(SeqStart, tempVertex);
//			tempVertex=m_seqGraph->getVertexByID((*path2)[0]->vidInGraph);
//			double multi2 = m_seqGraph->getMultiplicity(SeqStart, tempVertex);
//			if (multi1 > multi2 && path2->size() == 1) {
//				return path1;
//			} else if (multi2 > multi1 && path1->size() == 1) {
//				return path2;
//			} else {
//				return NULL;
//			}
//	}
//	delete[] buffer, path1seq, path2seq;
//	return NULL;
//}
//
//void SimpleRemoveBubbles::removePath(deque<VisitVertex*>* path) {
//	m_seqGraph->removeVertexAndTwin(m_seqGraph->getVertexByID((*path)[0]->vidInGraph)); // since only path containing one vertex can be remove in this consideration
//}

SequenceGraph* RemoverLowCoveragePath::correctGraph()
{
	cout<< "Start remove low coverage..." <<endl;
	LOG(INFO) << "Start remove low coverage...";
	ofstream outf("../examples/coverageDistribution.txt");
	int mergeNum = 0;
	m_seqGraph->resetCursor();
	while (m_seqGraph->hasNext()) {
		SequenceVertex* v = m_seqGraph->next();
		outf << v->coverage() <<endl;
		if (v->coverage() < m_coverageThreshold) {
			vector<SequenceEdge> preds(v->getPredecessors());
			for (int i = 0; i < preds.size(); ++i) {
				SequenceVertex* pred = preds[i].end;
				if (pred == v) { continue; }
				m_seqGraph->removeSuccessorAndTwinPredecessor(pred, v);
				if (pred->numSuccessors() == 1 && pred->getSuccessors()[0].end->numPredecessors() == 1) {
					m_seqGraph->mergeVertexIntoLargeIDVertex(pred, pred->getSuccessors()[0].end);
					++mergeNum;
				}
			}
			vector <SequenceEdge> succs(v->getSuccessors());
			for (int i = 0; i < succs.size(); ++i) {
				SequenceVertex* succ = succs[i].end;
				if (succ == v) { continue; }
				m_seqGraph->removeSuccessorAndTwinPredecessor(v, succ);
				if (succ->numPredecessors() == 1 && succ->getPredecessors()[0].end->numSuccessors() == 1) {
					m_seqGraph->mergeVertexIntoLargeIDVertex(succ->getPredecessors()[0].end, succ);
					++mergeNum;
				}
			}
			m_seqGraph->removeVertexAndTwin(v);
			
			++m_numCorrected;
		}
	} // while (m_seqGraph->hasNext())
	outf.close();
	cout << "Merge Errors: " << mergeNum << endl;
	cout<< "Finish remove low coverage." <<endl;
	LOG(INFO) << "Finish remove low coverage.";
	return m_seqGraph;
}